Skip to content
lab components / Data Visualization

Chart

Present users with interactive graphical representations of data.

This is a Lab component!

That means it doesn't satisfy our definition of done and may be changed or even deleted. For an exact status, please reach out to the Fancy team through the dev_fancy or ux_fancy channels.

import { Chart } from "@siteimprove/fancylab";

#Intro

The Chart component is a tailored wrapper built for the Highcharts library within a React environment. It's designed to offer a seamless integration of Highcharts while incorporating customized features, improved accessibility, and enhanced usability.

#Key Features

  • Customizations: The Chart component provides predefined customizations regarding colors, sizes, and themes to maintain consistency and visual appeal across charts.
  • Accessibility Improvements: Accessibility is a prime focus. The component ensures that charts are optimized for screen readers and other assistive technologies, making data visualization more inclusive.
  • Enhanced Usability: With improved interaction elements and intuitive functionalities, the Chart component aims to enhance user experience and ease of navigation within the charts.
  • Highcharts Features: Developers have full access to all Highcharts features, allowing them to leverage the extensive capabilities of Highcharts to create sophisticated and detailed charts.

#Support and Troubleshooting

The Chart component strives to ensure a seamless experience with Highcharts integrations. If you encounter any issues or discrepancies specific to the Chart component that differ from the standard Highcharts behavior, please reach out to us for support. If the issue works as expected with Highcharts in its raw form, kindly let us know to address the compatibility concern.

#Examples

The examples below showcase the various kinds of charts suported by Highcharts, such as line charts, column charts, and more (coming soon). Click on the tabs to view the examples.

For general features and functionalities, please refer to the Miscellaneous section.



#Basic usage

<Chart options={{ series: [ { type: "line", name: "Series 1", data: [25, 23, 48, 52, 52, 57, 56, 61, 66].map((val, i) => { return { x: i, y: val, name: i.toString(), customValue: "customValue1", }; }), }, { type: "line", name: "Series 2", data: [18, 26, 36, 44, 49, 59, 65, 71, 82].map((val, i) => { return { x: i, y: val, name: i.toString(), customValue: "customValue2", }; }), }, ], }} {...translations} />

#Usage with categories

<Chart options={{ xAxis: { categories: ["Apples", "Bananas", "Oranges", "Strawberries"], tickInterval: 1, }, series: [ { type: "line", name: "Series 1", data: [25, 23, 48, 52], }, { type: "line", name: "Series 2", data: [18, 26, 36, 44], }, ], }} {...translations} />

#Usage with X axis showing time

<Chart options={{ xAxis: { type: "datetime", // Set interval of tick marks to one month. For datetime axes this is based on milliseconds. tickInterval: 24 * 3600 * 1000 * 30, }, series: [ { type: "line", name: "Series 1", dashStyle: "ShortDot", data: [ { x: Date.UTC(2010, 0, 1), y: 10, }, { x: Date.UTC(2010, 1, 2), y: 20, }, { x: Date.UTC(2010, 2, 3), y: 30, }, { x: Date.UTC(2010, 3, 4), y: 40, }, { x: Date.UTC(2010, 4, 5), y: 50, }, ], }, { type: "line", name: "Series 2", data: [ { x: Date.UTC(2010, 0, 1), y: 20, }, { x: Date.UTC(2010, 1, 2), y: 30, }, { x: Date.UTC(2010, 2, 3), y: 40, }, { x: Date.UTC(2010, 3, 4), y: 50, }, { x: Date.UTC(2010, 5, 5), y: 60, }, ], }, ], }} {...translations} />

#Usage with multiple Y axes

<Chart options={{ xAxis: [ { type: "datetime", // Set interval of tick marks to one month. For datetime axes this is based on milliseconds. tickInterval: 24 * 3600 * 1000 * 30, }, ], yAxis: [{}, { opposite: true }], series: [ { type: "line", name: "Series 1", data: [ { x: Date.UTC(2010, 0, 1), y: 10, }, { x: Date.UTC(2010, 1, 1), y: 20, }, { x: Date.UTC(2010, 2, 1), y: 30, }, { x: Date.UTC(2010, 3, 1), y: 40, }, { x: Date.UTC(2010, 4, 1), y: 50, }, ], }, { type: "line", name: "Series 2", data: [ { x: Date.UTC(2010, 0, 1), y: 20, }, { x: Date.UTC(2010, 1, 1), y: 30, }, { x: Date.UTC(2010, 2, 1), y: 40, }, { x: Date.UTC(2010, 3, 1), y: 50, }, { x: Date.UTC(2010, 5, 1), y: 60, }, ], }, { type: "line", name: "Series 3", data: [ { x: Date.UTC(2010, 0, 1), y: 25, }, { x: Date.UTC(2010, 1, 1), y: 50, }, { x: Date.UTC(2010, 2, 1), y: 75, }, { x: Date.UTC(2010, 3, 1), y: 90, }, { x: Date.UTC(2010, 5, 1), y: 105, }, ], yAxis: 1, }, ], }} {...translations} />

#Usage with several series

<Chart options={{ series: [ { type: "line", name: "Series 1", data: [1.12, 1.14, 1.13, 1.16, 1.18, 1.17, 1.15, 1.19, 1.2, 1.22].map((val, i) => { return { x: i, y: val, name: i.toString(), }; }), }, { type: "line", name: "Series 2", data: [1.01, 1.05, 1.1, 1.09, 1.05, 1.02, 1.0, 1.01, 1.01, 1.02].map((val, i) => { return { x: i, y: val, name: i.toString(), }; }), }, { type: "line", name: "Series 3", data: [0.9, 1.01, 1.02, 1.03, 1.02, 1.0, 0.98, 0.96, 0.95, 0.99].map((val, i) => { return { x: i, y: val, name: i.toString(), }; }), }, { type: "line", name: "Series 4", data: [1.5, 1.6, 1.65, 1.7, 1.75, 1.78, 1.78, 1.79, 1.8, 1.8].map((val, i) => { return { x: i, y: val, name: i.toString(), }; }), }, { type: "line", name: "Series 5", data: [1.4, 1.38, 1.35, 1.31, 1.3, 1.3, 1.29, 1.28, 1.3, 1.32].map((val, i) => { return { x: i, y: val, name: i.toString(), }; }), }, { type: "line", name: "Series 6", data: [1.0, 1.1, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0].map((val, i) => { return { x: i, y: val, name: i.toString(), }; }), }, ], }} {...translations} />

#Usage with Annotations

Annotations are designed to be easily adaptable to any backend. For that, you can map your own data structure to our Annotations interface which has the following definition:

type AnnotationItem = { id: string | number; date: Date; comment: string; createdBy: string; visibility: string; isFavorite: boolean; visibleIn: string[]; username: string; }

In addition, the Chart component also provides properties for handling all basic annotation operations, such as creation (onCreateAnnotation), update (onUpdateAnnotation), and deletion (onDeleteAnnotation).

In the example below, the API object simulates the implementation of these methods and also provides a list of annotations according to the AnnotationItem interface.

Show:

const chartDateOptions: DateOptions = { locale: "en-us", skipTimezoneReset: false, }; const [annotationsData, setAnnotationsData] = useState<AnnotationItem[]>([]); const [annotationsAreasVisibleIn, setAnnotationsAreasVisibleIn] = useState< AnnotationAreasVisibleIn[] >([]); useEffect(() => { let isDataFetchDone = true; API.fetch().then((data) => isDataFetchDone && setAnnotationsData(data)); API.fetchAreasVisibleIn().then( (areas) => isDataFetchDone && setAnnotationsAreasVisibleIn(areas) ); return () => { isDataFetchDone = false; }; }, []); return ( <Chart options={{ xAxis: { type: "datetime", // Set interval of tick marks to one month. For datetime axes this is based on milliseconds. tickInterval: 24 * 3600 * 1000 * 30, }, series: [ { type: "line", name: "Series 1", data: [ { x: Date.UTC(2022, 1, 1), y: 20, }, { x: Date.UTC(2022, 2, 1), y: 30, }, { x: Date.UTC(2022, 3, 1), y: 40, }, { x: Date.UTC(2022, 4, 1), y: 50, }, { x: Date.UTC(2022, 5, 1), y: 30, }, ], }, { type: "line", name: "Series 2", data: [ { x: Date.UTC(2022, 0, 1), y: 20, }, { x: Date.UTC(2022, 1, 1), y: 30, }, { x: Date.UTC(2022, 2, 1), y: 40, }, { x: Date.UTC(2022, 3, 1), y: 50, }, { x: Date.UTC(2022, 5, 1), y: 60, }, ], }, ], }} {...translations} showAnnotationButton annotations={annotationsData} chartPeriod={[new Date(2022, 0, 1), new Date(2022, 3, 1)]} onUpdateAnnotation={async (data: Omit<Partial<AnnotationItem>, "createdBy">) => { await API.update(data); setAnnotationsData(await API.fetch()); }} onCreateAnnotation={async (data: Omit<AnnotationItem, "id" | "createdBy">) => { await API.create(data); setAnnotationsData(await API.fetch()); }} onDeleteAnnotation={async (id: string | number) => { await API.delete(id); setAnnotationsData(await API.fetch()); }} chartDateOptions={chartDateOptions} annotationAreasVisibleIn={annotationsAreasVisibleIn} /> );

#Miscellaneous

These examples showcase the various features and functionalities of the Chart component that are not specific to any particular chart type. It includes features such as legends, tooltips, sizes, and more.

#Usage with reference lines

const { ColorRed, ColorTextStaticBody } = useDesignToken(); return ( <Chart options={{ yAxis: { plotLines: [ { value: 70, color: ColorRed, width: 3, dashStyle: "ShortDot", label: { text: "Limit (70)", align: "right", x: -5, style: { color: ColorTextStaticBody, }, }, }, ], }, series: [ { type: "line", name: "Series 1", data: [25, 23, 48, 52, 52, 57, 56, 61, 66].map((val, i) => { return { x: i, y: val, name: i.toString(), }; }), }, { type: "line", name: "Series 2", data: [15, 13, 38, 42, 42, 47, 46, 51, 56].map((val, i) => { return { x: i, y: val, name: i.toString(), }; }), }, ], }} {...translations} /> );

#Usage with no legend

<Chart options={{ plotOptions: { series: { showInLegend: false, }, }, series: [ { type: "column", name: "Series 1", data: [25, 23, 48, 52, 52, 57, 56, 61, 66].map((val, i) => { return { x: i, y: val, name: i.toString(), customValue: "customValue1", }; }), }, { type: "line", name: "Series 2", data: [18, 26, 36, 44, 49, 59, 65, 71, 82].map((val, i) => { return { x: i, y: val, name: i.toString(), customValue: "customValue2", }; }), }, ], }} {...translations} />

#Usage with series hidden on load

<Chart options={{ series: [ { type: "column", name: "Series 1", data: [25, 23, 48, 52, 52, 57, 56, 61, 66].map((val, i) => { return { x: i, y: val, name: i.toString(), }; }), }, { type: "line", name: "Series 2", data: [18, 26, 36, 44, 49, 59, 65, 71, 82].map((val, i) => { return { x: i, y: val, name: i.toString(), }; }), selected: false, }, ], }} {...translations} />

#Usage with series not visible in the legends

<Chart options={{ series: [ { type: "column", name: "Series 1", data: [25, 23, 48, 52, 52, 57, 56, 61, 66].map((val, i) => { return { x: i, y: val, name: i.toString(), }; }), }, { showInLegend: false, type: "line", name: "Series 2", data: [18, 26, 36, 44, 49, 59, 65, 71, 82].map((val, i) => { return { x: i, y: val, name: i.toString(), }; }), }, ], }} {...translations} />

#Usage with missing data

If all series contain empty data (undefined, null or NaN) in a determined position, the row will not be displayed on the table visualization.

<Chart options={{ series: [ { type: "column", name: "Series 1", data: [25, 23, 48, 52, undefined, 52, 57, 56, 61].map((val, i) => { return { x: i, y: val, }; }), }, { type: "line", name: "Series 2", data: [18, 26, 36, 44, undefined, 49, 59, 65, 71].map((val, i) => { return { x: i, y: val, }; }), }, ], }} {...translations} />

#Usage with tooltip formatters

The header of the chart tooltip can be formatted using the optional property tooltipHeaderFormatter with the values default, named, and keyed.

The individual points of the chart tooltip can be formatted using the optional property tooltipPointFormatter with the values default, named, and customValue.

<Chart options={{ series: [ { type: "column", name: "Series 1", data: [25, 23, 48, 52, 52, 57, 56, 61, 66].map((val, i) => { return { x: i, y: val, name: "Name for x: " + i.toString(), customValue: "Custom value for x: " + i.toString() + " in series 1", }; }), }, { type: "line", name: "Series 2", data: [18, 26, 36, 44, 49, 59, 65, 71, 82].map((val, i) => { return { x: i, y: val, name: "Name for x: " + i.toString(), customValue: "Custom value for x: " + i.toString() + " in series 2", }; }), }, ], }} {...translations} tooltipHeaderFormatter="named" tooltipPointFormatter="customValue" />

#Visual

#Height

Use the height property to adjust the chart size. The default height is medium (310px) and should be used in most cases. Use small height when space is limited. Use large or a custom value when the previous sizes are not suitable.

function BaseChart(props: { height: ChartProps["height"] }) { return ( <> <InlineText emphasis="medium">{props.height}</InlineText> <br /> <Chart height={props.height} hideContextMenu options={{ series: [ { type: "line", name: "Series 1", data: [25, 23, 48, 52, 52, 57, 56, 61, 66].map((val, i) => { return { x: i, y: val, name: val.toString(), }; }), }, ], }} {...translations} /> </> ); } return ( <> <BaseChart height="small" /> <BaseChart height="medium" /> <BaseChart height="large" /> </> );

#Usage with context menu changes

Use the hideContextMenu property to remove the Context Menu gear icon. The default setting is to show the Context Menu. In addition, use the hideEnhancedContrastOption property to remove the Enhanced contrast option from the Conext menu when that is visible. The default setting is to show the Enhanced Contrast option.

In the example below, the hideContextMenu is disabled and the hideEnhancedContrastOption is enabled.

<Chart hideContextMenu={false} hideEnhancedContrastOption options={{ series: [ { type: "column", name: "Series 1", data: [25, 23, 48, 52, 52, 57, 56, 61, 66].map((val, i) => { return { x: i, y: val, name: i.toString(), customValue: "customValue1", }; }), }, { type: "line", name: "Series 2", data: [18, 26, 36, 44, 49, 59, 65, 71, 82].map((val, i) => { return { x: i, y: val, name: i.toString(), customValue: "customValue2", }; }), }, ], }} {...translations} />

#Usage with persistent legend state

Use the onToggleSeries property to persist the legend state. The default setting is to not persist the legend state, which means that the legend state will be reset when the page is refreshed. The visibility state of each series is controlled by the visible property of the series object.

const [series, setSeries] = useState<Highcharts.SeriesOptionsType[]>([ { type: "column", name: "Series 1", visible: true, data: [25, 23, 48, 52, 52, 57, 56, 61, 66].map((val, i) => { return { x: i, y: val, name: i.toString(), customValue: "customValue1", }; }), }, { type: "line", name: "Series 2", visible: false, data: [18, 26, 36, 44, 49, 59, 65, 71, 82].map((val, i) => { return { x: i, y: val, name: i.toString(), customValue: "customValue2", }; }), }, ]); return ( <Chart onToggleSeries={(seriesIndex, visible) => { const newSeries = [...series]; newSeries[seriesIndex].visible = visible; setSeries(newSeries); console.log( "Save series visibility to user preferences (e.g.: localStorage)", seriesIndex, visible ); }} options={{ series }} {...translations} /> );

#Data updates

The Chart component automatically updates the chart when the options or height properties change. This is useful when the chart data is updated dynamically or the layout changes and the chart needs to be redrawn.

const numberOfSeries = 2; const seriesLength = 10; const buildData = () => generateRandomData(numberOfSeries, seriesLength); const [series, setSeries] = useState<number[][]>(buildData()); return ( <Content> <Button onClick={() => setSeries(buildData())}>Generate series</Button> <Chart options={{ series: [ { type: "column", name: "Series 1", data: series[0].map((val, i) => { return { x: i, y: val, name: i.toString(), customValue: "customValue1", }; }), }, { type: "line", name: "Series 2", data: series[1].map((val, i) => { return { x: i, y: val, name: i.toString(), customValue: "customValue2", }; }), }, ], }} {...translations} /> </Content> );

#Usage with no data

In some real-world scenarios, the chart may not have any data to display. In this case, the chart frame and the table view will be empty.

<Chart options={{ series: [], }} {...translations} />

#Properties

PropertyDescriptionDefinedValue
optionsRequired
objectOptions for Highcharts chart
screenReaderRegionLabelRequired
stringLabel for screen reader region
screenReaderChartHeadingRequired
stringLabel for chart
defaultChartTitleRequired
stringDefault chart label
tableSummaryRequired
stringSummary for the data displayed in the data table
chartContainerLabelRequired
stringLabel for chart container
legendItemRequired
stringLegend item label
chartTypesMapTypeDescriptionRequired
stringDescription for chart type map type
chartTypesCombinationChartRequired
stringDescription for chart type combination chart
chartTypesDefaultSingleRequired
stringDescription for chart type default single
chartTypesDefaultMultipleRequired
stringDescription for chart type default multiple
chartTypesSplineSingleRequired
stringDescription for chart type spline single
chartTypesSplineMultipleRequired
stringDescription for chart type spline multiple
chartTypesLineSingleRequired
stringDescription for chart type line single
chartTypesLineMultipleRequired
stringDescription for chart type line multiple
chartTypesColumnSingleRequired
stringDescription for chart type column single
chartTypesColumnMultipleRequired
stringDescription for chart type column multiple
chartTypesBarSingleRequired
stringDescription for chart type bar single
chartTypesBarMultipleRequired
stringDescription for chart type bar multiple
chartTypesPieSingleRequired
stringDescription for chart type pie single
chartTypesPieMultipleRequired
stringDescription for chart type pie multiple
xAxisDescriptionSingularRequired
stringDescription for x-axis singluar
xAxisDescriptionPluralRequired
stringDescription for x-axis plural
categoryColumnHeaderRequired
stringTable column header for x-axis when the type is "category", "linear", or "logarithmic"
datetimeColumnHeaderRequired
stringTable column header for x-axis when the type is "datetime"
yAxisDescriptionSingularRequired
stringDescription for y-axis singluar
yAxisDescriptionPluralRequired
stringDescription for y-axis plural
chartSeriesDefaultRequired
stringChart series summary default
chartSeriesDefaultCombinationRequired
stringChart series summary default combination
chartSeriesLineRequired
stringChart series summary line
chartSeriesLineCombinationRequired
stringChart series summary line combination
chartSeriesSplineRequired
stringChart series summary spline
chartSeriesSplineCombinationRequired
stringChart series summary spline combination
chartSeriesColumnRequired
stringChart series summary column
chartSeriesColumnCombinationRequired
stringChart series summary column combination
chartSeriesBarRequired
stringChart series summary bar
chartSeriesBarCombinationRequired
stringChart series summary bar combination
chartSeriesPieRequired
stringChart series summary pie
chartSeriesScatterCombinationRequired
stringChart series summary pie combination
chartSeriesMapCombinationRequired
stringChart series summary map combination
chartSeriesMapbubbleCombinationRequired
stringChart series summary mapbubble combination
xAxisDescriptionRequired
stringDescription of x-axis
yAxisDescriptionRequired
stringDescription of y-axis
contextMenuForLabelRequired
stringLabel for the context menu. It will be appended with the chart title.
contextMenuEnhancedContrastLabelRequired
stringLabel for the enhanced contrast button in the context menu
contextMenuEnhancedContrastTooltipRequired
stringTooltip content for the enhanced contrast button
contextMenuTableViewLabelRequired
stringLabel for table view button in the context menu
contextMenuTableViewTooltipRequired
stringTooltip content for the table view button
showAnnotationButtonOptional
booleanShould show annotation button
annotationsOptional
object[]Annotations array
chartPeriodOptional
date[]Chart Period (for Annotations)
onUpdateAnnotationOptional
functionPUT call to update Annotation
onCreateAnnotationOptional
functionCREATE new Annotation
onDeleteAnnotationOptional
functionDELETE new Annotation
chartDateOptionsOptional
objectDate Options for the chart annotations
annotationAreasVisibleInOptional
object[]Array of areas to allow annotations to be visible in
heightOptional
| string | numberChart height (default medium, i.e. 310px)
containerClassNameOptional
stringCSS class for the Highcharts wrapper
useHighchartsLegendOptional
booleanUse native Highcharts legend
onToggleSeriesOptional
functionCallback for toggling series visibility
hideContextMenuOptional
booleanHides the context menu icon
hideEnhancedContrastOptionOptional
booleanHides the enhanced contrast context option
overflowableOptional
booleanShould overflow be allowed (if not, tooltip might be cut off)
a11yModeOptional
booleanEnables enhanced contrast mode
tooltipHeaderFormatterOptional
"default" | "keyed" | "named"Tooltip header formatters
tooltipPointFormatterOptional
"customValue" | "default" | "named"Tooltip point formatters
data-observe-keyOptional
stringUnique string, used by external script e.g. for event tracking
classNameOptional
stringCustom className that's applied to the outermost element (only intended for special cases)
styleOptional
objectStyle object to apply custom inline styles (only intended for special cases)

#Guidelines

#Best practices

  • ...
  • ...

#Do not use when

  • ...
  • ...

#Accessibility

This component comes with built-in accessibility, no extra work required.

Explore detailed guidelines for this component: Accessibility Specifications

#Writing

  • ...
  • ...